package com.gao.weblog.admin.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gao.weblog.admin.model.vo.article.ArticleDetailVO;
import com.gao.weblog.admin.model.vo.article.ArticleVO;
import com.gao.weblog.admin.model.vo.article.PublishArticleDTO;
import com.gao.weblog.admin.service.AdminArticleService;
import com.gao.weblog.common.domain.dos.ArticleCategoryRelDO;
import com.gao.weblog.common.domain.dos.ArticleContentDO;
import com.gao.weblog.common.domain.dos.ArticleDO;
import com.gao.weblog.common.domain.dos.ArticleTagRelDO;
import com.gao.weblog.common.domain.dos.CategoryDO;
import com.gao.weblog.common.domain.dos.TagDO;
import com.gao.weblog.common.domain.mapper.ArticleCategoryRelMapper;
import com.gao.weblog.common.domain.mapper.ArticleContentMapper;
import com.gao.weblog.common.domain.mapper.ArticleMapper;
import com.gao.weblog.common.domain.mapper.ArticleTagRelMapper;
import com.gao.weblog.common.domain.mapper.CategoryMapper;
import com.gao.weblog.common.domain.mapper.TagMapper;
import com.gao.weblog.common.enums.ResponseCodeEnum;
import com.gao.weblog.common.exception.BizException;
import com.gao.weblog.common.model.dto.ArticleQueryDTO;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AdminArticleServiceImpl extends ServiceImpl<ArticleMapper, ArticleDO> implements AdminArticleService {
    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ArticleContentMapper articleContentMapper;

    @Autowired
    private ArticleCategoryRelMapper articleCategoryRelMapper;

    @Autowired
    private ArticleTagRelMapper articleTagRelMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Override
    public List<ArticleDO> findArticlePageList(ArticleQueryDTO articleQueryDTO) {

        Page<ArticleDO> articleDOPage = articleMapper.selectPageList(articleQueryDTO);

        return articleDOPage.getRecords();

    }

    @Override
    public ArticleDetailVO findArticleDetail(Long articleId) {

        ArticleDO articleDO = articleMapper.selectById(articleId);

        if (Objects.isNull(articleDO)) {
            log.warn("===> 查询的文章不存在，articleId: {}", articleId);
            throw new BizException(ResponseCodeEnum.ARTICLE_NOT_FOUND);
        }

        String content = articleContentMapper.selectByArticleId(articleId);
        Long categoryId = articleCategoryRelMapper.selectByArticleId(articleId);
        List<Long> tagIds = articleTagRelMapper.selectByArticleId(articleId);

        ArticleDetailVO articleDetailVO = new ArticleDetailVO();
        BeanUtils.copyProperties(articleDO, articleDetailVO);
        articleDetailVO.setCategoryId(categoryId);
        articleDetailVO.setTagIds(tagIds);
        articleDetailVO.setContent(content);

        return articleDetailVO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishArticle(PublishArticleDTO publishArticleDTO) {

        ArticleDO article = new ArticleDO();
        BeanUtils.copyProperties(article, publishArticleDTO);
        article.setCreateTime(LocalDateTime.now());
        article.setUpdateTime(LocalDateTime.now());
        articleMapper.insert(article);

        Long articleId = article.getId();

        insertContent(publishArticleDTO, articleId);
        insertCategory(publishArticleDTO, articleId);

        List<String> articleTags = publishArticleDTO.getTags();
        insertTags(articleId, articleTags);
    }

    private void insertCategory(PublishArticleDTO publishArticleDTO, Long articleId) {
        Long articleCategoryId = publishArticleDTO.getCategoryId();
        CategoryDO category = categoryMapper.selectById(articleCategoryId);
        if (Objects.isNull(category)) {
            log.warn("==> 分类不存在，categoryID：{}", articleCategoryId);
            throw new BizException(ResponseCodeEnum.CATEGORY_NOT_EXISTED);
        }

        ArticleCategoryRelDO articleCategoryRel = ArticleCategoryRelDO.builder()
                .articleId(articleId)
                .categoryId(articleCategoryId)
                .build();
        articleCategoryRelMapper.insert(articleCategoryRel);
    }

    private void insertContent(PublishArticleDTO publishArticleDTO, Long articleId) {
        ArticleContentDO articleContent = ArticleContentDO.builder()
                .articleId(articleId)
                .content(publishArticleDTO.getContent())
                .build();
        articleContentMapper.insert(articleContent);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteArticle(Long  articleId) {

        articleMapper.deleteById(articleId);
        articleTagRelMapper.deleteByArticleId(articleId);
        articleContentMapper.deleteByArticleId(articleId);
        articleCategoryRelMapper.deleteByArticleId(articleId);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ArticleVO updateArticle(ArticleVO articleVO) {

        ArticleDO articleDO = new ArticleDO();
        BeanUtils.copyProperties(articleVO, articleDO);
        articleDO.setUpdateTime(LocalDateTime.now());

        Long articleId = articleVO.getId();
        int count = articleMapper.updateById(articleDO);
        if (count == 0){
            log.warn("==> 该文章不存在, articleId: {}", articleId);
            throw new BizException(ResponseCodeEnum.ARTICLE_NOT_FOUND);
        }

        ArticleContentDO articleContentDO = new ArticleContentDO();
        BeanUtils.copyProperties(articleVO, articleContentDO);
        articleContentMapper.updateByArticleId(articleContentDO);

        Long categoryId = articleVO.getCategoryId();
        CategoryDO categoryDO = categoryMapper.selectById(categoryId);
        if (Objects.isNull(categoryDO)){
            log.warn("==> 分类不存在, categoryId: {}", categoryId);
            throw new BizException(ResponseCodeEnum.CATEGORY_NOT_EXISTED);
        }

        articleCategoryRelMapper.deleteByArticleId(articleId);
        ArticleCategoryRelDO articleCategoryRelDO = ArticleCategoryRelDO.builder()
                                                    .articleId(articleId)
                                                    .categoryId(categoryId)
                                                    .build();
        articleCategoryRelMapper.insert(articleCategoryRelDO);

        articleTagRelMapper.deleteByArticleId(articleId);
        List<String> publishTags = articleVO.getTags();
        insertTags(articleId, publishTags);

        return articleVO;
    }

    private void insertTags(Long articleId, List<String> publishTags) {
        List<String> notExistTags = null;
        List<String> existedTags = null;

        List<TagDO> tagDOS = tagMapper.selectList(null);

        if (CollectionUtils.isEmpty(tagDOS)) {
            notExistTags = publishTags;
        }else{
            List<String> tagIds = tagDOS.stream().map(tagDO -> String.valueOf(tagDO.getId())).collect(Collectors.toList());
            existedTags = publishTags.stream().filter(publishTag -> tagIds.contains(publishTag)).collect(Collectors.toList());
            notExistTags = publishTags.stream().filter(publishTag -> !tagIds.contains(publishTag)).collect(Collectors.toList());
            Map<String, Long> tagNameIdMap = tagDOS.stream().collect(Collectors.toMap(tagDO -> tagDO.getName().toLowerCase(), TagDO::getId));
            Iterator<String> iterator = notExistTags.iterator();
            while (iterator.hasNext()) {
                String notExistTag = iterator.next();
                if (tagNameIdMap.containsKey(notExistTag.toLowerCase())) {
                    iterator.remove();
                    existedTags.add(String.valueOf(tagNameIdMap.get(notExistTag.toLowerCase())));
                }
            }
        }

        if (!CollectionUtils.isEmpty(existedTags)) {
            List<ArticleTagRelDO> articleTagRelDOS = Lists.newArrayList();
            existedTags.forEach(tagId -> {
                ArticleTagRelDO articleTagRelDO = ArticleTagRelDO.builder()
                        .articleId(articleId)
                        .tagId(Long.valueOf(tagId))
                        .build();
                articleTagRelDOS.add(articleTagRelDO);
            });
            articleTagRelMapper.insertBatchSomeColumn(articleTagRelDOS);
        }

        if (!CollectionUtils.isEmpty(notExistTags)) {
            List<ArticleTagRelDO> articleTagRelDOS = Lists.newArrayList();
            notExistTags.forEach(tagName -> {
                TagDO tagDO = TagDO.builder()
                        .name(tagName)
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .build();
                tagMapper.insert(tagDO);
                Long tagId = tagDO.getId();
                ArticleTagRelDO articleTagRelDO = ArticleTagRelDO.builder()
                        .articleId(articleId)
                        .tagId(tagId)
                        .build();
                articleTagRelDOS.add(articleTagRelDO);
            });
            articleTagRelMapper.insertBatchSomeColumn(articleTagRelDOS);
        }
    }
}
